package cn.ting.mybatis.executor;

import cn.ting.mybatis.cache.Cache;
import cn.ting.mybatis.cache.CacheWapper;
import cn.ting.mybatis.po.Configuration;
import cn.ting.mybatis.po.Mapper;
import cn.ting.mybatis.proxy.Converser;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: ting
 */
public class MyExecutor implements Executor{



    private Configuration configuration;

    private static String SQL = "sql";
    private static String RESULT_TYPE = "resultType";

    private Cache cache;

    public MyExecutor(Configuration configuration) {
        this.configuration = configuration;//把opensession中传的myConfiguration传给当前类的成员变量

    }



    public Map<String,String> getSqlandResultType(String Key){
        //2.获取SQl语句
        Map<String, Mapper> mappers = configuration.getMappers();
        Mapper mapper = mappers.get(Key);
        String sql = mapper.getSql();
        String resultType = mapper.getResultType();
        Map<String,String> res = new HashMap<String, String>();
        res.put(SQL,sql);
        res.put(RESULT_TYPE,resultType);
        return res;
    }


    public <T> List<T> selectList(String Key){
        Connection connection = null;
        PreparedStatement pstm = null;
        ResultSet resultSet = null;
        try {
            //1.获取连接对象
            connection = configuration.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        Map<String,String> map = getSqlandResultType(Key);

        //查看缓存是否命中
        int cacheKey = (map.get(SQL) + map.get(RESULT_TYPE)).hashCode();
        cache = CacheWapper.getCache(this);
        if(cache != null && cache.getObject(cacheKey) != null){
            System.out.println("命中缓存List");
            return (List<T>) cache.getObject(cacheKey);
        }

        try {
            //3.预编译SQL语句
            pstm = connection.prepareStatement(map.get(SQL));
            //4.执行Sql语句
            resultSet = pstm.executeQuery();
            //5.将结果集封装到JavaBean里面----->反射技术
            List<T> list = Converser.converList(resultSet, Class.forName(map.get(RESULT_TYPE)));

            //未命中查询后加入缓存
            cache.putObject(cacheKey,list);
            return list;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }finally {
            close(connection,pstm,resultSet);
        }
    }


    public Object query(String Key,Object parameter){
        Connection connection = null;
        PreparedStatement pstm = null;
        ResultSet resultSet = null;
        try {
            //1.获取连接对象
            connection = configuration.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //2.获取SQl语句
        Map<String,String> map = getSqlandResultType(Key);

        //查看缓存是否命中
        int cacheKey = (map.get(SQL) + map.get(RESULT_TYPE) + parameter).hashCode();
        cache = CacheWapper.getCache(this);
        if(cache != null && cache.getObject(cacheKey) != null){
            System.out.println("命中缓存Object");
            return  cache.getObject(cacheKey);
        }

        try {
            //3.预编译SQL语句
          pstm = connection.prepareStatement(map.get(SQL));

          // pstm = connection.prepareStatement(SQLTokenParser.parse(sql));

            //设置参数
            if (parameter instanceof Integer) {
                pstm.setInt(1, (Integer) parameter);
            } else {
            }


            //4.执行Sql语句
            resultSet = pstm.executeQuery();
            //5.将结果集封装到JavaBean里面----->反射技术
            Object res =  Converser.converSelectid(resultSet, Class.forName(map.get(RESULT_TYPE)));

            //加入缓存
            cache.putObject(cacheKey,res);
            return res;

        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }finally {
            close(connection,pstm,resultSet);
        }
    }


    public int delete(String Key,Object parameter){
        Connection connection = null;
        PreparedStatement pstm = null;
        ResultSet resultSet = null;
        try {
            //1.获取连接对象
            connection = configuration.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //2.获取SQl语句
        Map<String,String> map = getSqlandResultType(Key);

        //有非查询操作清空缓存
        clearCache();
        try {

            //3.预编译SQL语句
            pstm = connection.prepareStatement(map.get(SQL));

            // pstm = connection.prepareStatement(SQLTokenParser.parse(sql));

            //设置参数
            if (parameter instanceof Integer) {
                pstm.setInt(1, (Integer) parameter);
            } else {
            }


            //4.执行Sql语句
            int res= pstm.executeUpdate();
            //boolean res = pstm.execute();
            //5.将结果集封装到JavaBean里面----->反射技术
           // return Converser.converDeleteid(resultSet, Class.forName(resultType));
             return res;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }finally {
            close(connection,pstm,resultSet);
        }
    }




    public int update(String Key,String parameter){

        Connection connection = null;
        PreparedStatement pstm = null;
        ResultSet resultSet = null;
        try {
            //1.获取连接对象
            connection = configuration.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //2.获取SQl语句
        Map<String,String> map = getSqlandResultType(Key);

        //有非查询操作清空缓存
        clearCache();
        try {
            String[] str = parameter.split(" ");

            int id = Integer.valueOf(str[0]);
            String username=str[1];
            String birthday=str[2];
            String sex=str[3];
            String address=str[4];

            //3.预编译SQL语句
            pstm = connection.prepareStatement(map.get(SQL));

            // pstm = connection.prepareStatement(SQLTokenParser.parse(sql));

            //设置参数
            pstm.setInt(5, id);
            pstm.setString(1,username);
            pstm.setString(2,birthday);
            pstm.setString(3,sex);
            pstm.setString(4,address);

            //4.执行Sql语句
            int res = pstm.executeUpdate();

            return res;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException();
        }finally {
            close(connection,pstm,resultSet);
        }
    }

    public void close(Connection connection, PreparedStatement pstm, ResultSet resultSet){
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (pstm != null) {
                pstm.close();
            }
            if (connection != null) {
                connection.close();
            }
        }catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void clearCache() {
        Cache cache = CacheWapper.getCache(this);
        cache.clear();
    }

}
